import tkinter as tk
from tkinter import messagebox
import requests
import threading
import json
import os
from json import JSONDecodeError
from urllib.parse import urlparse


class APIApp:
    def __init__(self, root):
        self.root = root

        # 初始化所有变量
        self.url_var = tk.StringVar(value="http://127.0.0.1:5000/api/reportApi/report")
        self.line_code_var = tk.StringVar(value="")
        self.station_code_var = tk.StringVar(value="")
        self.sn_count_var = tk.StringVar(value="1")
        self.need_result_var = tk.BooleanVar(value=True)
        self.judge_char_1_var = tk.StringVar(value="01")
        self.judge_result_1_var = tk.StringVar(value="OK")
        self.judge_char_2_var = tk.StringVar(value="00")
        self.judge_result_2_var = tk.StringVar(value="NG")
        self.sn_entries = []
        self.result_entries = []

        # 加载设置
        self.load_settings()

        # 初始化 UI
        self.setup_ui()

    def update_title(self):
        """更新主窗口标题"""
        line_code = self.line_code_var.get() or "未设置"
        station_code = self.station_code_var.get() or "未设置"
        self.root.title(f"API 发送端 - {line_code}-{station_code}")

    def load_settings(self):
        """加载保存的设置"""
        try:
            if os.path.exists('settings.json'):
                with open('settings.json', 'r') as f:
                    settings = json.load(f)
                    self.url_var.set(settings.get('url', "http://127.0.0.1:5000/api/reportApi/report"))
                    self.line_code_var.set(settings.get('lineCode', ''))
                    self.station_code_var.set(settings.get('stationCode', ''))
                    self.sn_count_var.set(settings.get('sn_count', '1'))
                    self.need_result_var.set(settings.get('need_result', True))
                    self.judge_char_1_var.set(settings.get('judge_char_1', '01'))
                    self.judge_result_1_var.set(settings.get('judge_result_1', 'OK'))
                    self.judge_char_2_var.set(settings.get('judge_char_2', '00'))
                    self.judge_result_2_var.set(settings.get('judge_result_2', 'NG'))
            self.update_title()
        except (JSONDecodeError, FileNotFoundError):
            pass  # 使用默认值
        except Exception as e:
            messagebox.showerror("错误", f"加载设置时出错: {str(e)}")

    def setup_ui(self):
        """初始化用户界面"""
        # 主框架
        main_frame = tk.Frame(self.root, padx=10, pady=10)
        main_frame.pack(expand=True, fill=tk.BOTH)

        # 按钮栏
        button_frame = tk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=5)

        tk.Button(button_frame, text="设置", command=self.open_settings_window).pack(side=tk.LEFT)
        tk.Button(button_frame, text="发送请求", command=self.send_request).pack(side=tk.LEFT, padx=5)

        # SN 输入区域
        self.sn_frame = tk.Frame(main_frame)
        self.sn_frame.pack(fill=tk.X, pady=10)
        self.update_sn_inputs()

        # 结果显示区域
        result_frame = tk.Frame(main_frame)
        result_frame.pack(fill=tk.BOTH, expand=True)

        self.result_text = tk.Text(result_frame, height=10, width=80)
        self.result_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        scrollbar = tk.Scrollbar(result_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.result_text.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.result_text.yview)

        # 右键菜单
        self.right_click_menu = tk.Menu(self.root, tearoff=0)
        self.right_click_menu.add_command(label="清除历史数据", command=self.clear_result_text)
        self.result_text.bind("<Button-3>", self.show_right_click_menu)

    def send_request(self):
        """发送请求到 API"""
        def perform_request():
            url = self.url_var.get()
            if not self.validate_url(url):
                self.update_result("错误: 无效的 URL 格式，请使用 http:// 或 https:// 开头")
                return

            try:
                line_code = self.line_code_var.get()
                station_code = self.station_code_var.get()
                sn_list = [entry.get() for entry in self.sn_entries]

                if not all(sn_list):
                    self.show_error("错误", "请输入所有产品 SN")
                    return

                if self.need_result_var.get():
                    result_list = [entry.get() for entry in self.result_entries]
                    if not all(result_list):
                        self.show_error("错误", "请输入所有检测结果")
                        return
                    # 转换结果为自定义字符
                    result_list = [
                        self.judge_result_1_var.get() if res.upper() == self.judge_char_1_var.get().upper() else self.judge_result_2_var.get()
                        for res in result_list
                    ]
                else:
                    result_list = [self.judge_result_1_var.get()] * len(sn_list)

                for i, sn in enumerate(sn_list):
                    data = {
                        "lineCode": line_code,
                        "stationCode": station_code,
                        "sn": sn,
                        "qty": 1,
                        "result": result_list[i]
                    }

                    try:
                        response = requests.post(url, json=data, timeout=10)
                        self.handle_response(response, sn)
                    except requests.exceptions.Timeout:
                        self.update_result(f"错误: 请求超时，SN: {sn}，请检查网络连接")
                    except requests.exceptions.ConnectionError:
                        self.update_result(f"错误: 无法连接到服务器，SN: {sn}，请检查 URL 是否正确: {url}")
                    except requests.exceptions.RequestException as e:
                        self.update_result(f"请求错误，SN: {sn}: {str(e)}")
                    except Exception as e:
                        self.update_result(f"意外错误，SN: {sn}: {str(e)}")

                self.clear_inputs()

            except Exception as e:
                self.update_result(f"请求处理错误: {str(e)}")

        threading.Thread(target=perform_request).start()

    def handle_response(self, response, sn):
        """处理 API 响应"""
        try:
            if response.status_code == 404:
                error_msg = (
                    f"状态码: 404，SN: {sn}\n"
                    f"错误: 请求的资源不存在\n"
                    f"可能原因:\n"
                    f"1. URL 路径错误: {self.url_var.get()}\n"
                    f"2. 后端服务未运行\n"
                    f"3. API 端点不存在\n"
                    f"原始响应: {response.text[:200]}..."
                )
                self.update_result(error_msg)
                return

            if response.status_code == 200:
                try:
                    response_data = response.json()
                    status = f"状态码: 200，SN: {sn}\n响应内容: {json.dumps(response_data, indent=2, ensure_ascii=False)}"
                except JSONDecodeError:
                    status = f"状态码: 200，SN: {sn}\n警告: 响应不是有效的 JSON\n原始内容: {response.text[:200]}..."
            else:
                try:
                    error_data = response.json()
                    status = f"状态码: {response.status_code}，SN: {sn}\n错误响应: {json.dumps(error_data, indent=2, ensure_ascii=False)}"
                except JSONDecodeError:
                    status = f"状态码: {response.status_code}，SN: {sn}\n错误响应(非 JSON): {response.text[:200]}..."

            self.update_result(status)

        except Exception as e:
            self.update_result(f"响应处理错误，SN: {sn}: {str(e)}")

    def validate_url(self, url):
        """验证 URL 格式"""
        try:
            result = urlparse(url)
            return all([result.scheme in ('http', 'https'), result.netloc])
        except:
            return False

    def update_result(self, message):
        """更新结果显示区域"""
        self.root.after(0, lambda: self._update_result(message))

    def _update_result(self, message):
        """内部方法：更新结果文本"""
        current_text = self.result_text.get(1.0, tk.END).strip()
        if current_text:
            new_text = current_text + "\n\n" + message
        else:
            new_text = message
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, new_text)
        self.result_text.see(tk.END)

    def clear_inputs(self):
        """清空输入框"""
        for entry in self.sn_entries:
            entry.delete(0, tk.END)
        for entry in self.result_entries:
            entry.delete(0, tk.END)
        if self.sn_entries:
            self.sn_entries[0].focus_set()

    def clear_result_text(self):
        """清除历史数据"""
        self.result_text.delete(1.0, tk.END)

    def show_right_click_menu(self, event):
        """显示右键菜单"""
        try:
            self.right_click_menu.tk_popup(event.x_root, event.y_root)
        finally:
            self.right_click_menu.grab_release()

    def show_error(self, title, message):
        """显示错误消息"""
        self.root.after(0, lambda: messagebox.showerror(title, message))

    def save_settings(self):
        """保存设置到文件"""
        try:
            settings = {
                "url": self.url_var.get(),
                "lineCode": self.line_code_var.get(),
                "stationCode": self.station_code_var.get(),
                "sn_count": self.sn_count_var.get(),
                "need_result": self.need_result_var.get(),
                "judge_char_1": self.judge_char_1_var.get(),
                "judge_result_1": self.judge_result_1_var.get(),
                "judge_char_2": self.judge_char_2_var.get(),
                "judge_result_2": self.judge_result_2_var.get()
            }
            with open('settings.json', 'w') as f:
                json.dump(settings, f)
            self.update_title()
            self.update_sn_inputs()
            return True
        except Exception as e:
            messagebox.showerror("错误", f"保存设置时出错: {str(e)}")
            return False

    def open_settings_window(self):
        """打开设置窗口"""
        settings_window = tk.Toplevel(self.root)
        settings_window.title("设置")
        settings_window.resizable(True, True)

        # 使用 Frame 作为容器
        container = tk.Frame(settings_window, padx=10, pady=10)
        container.pack(expand=True, fill=tk.BOTH)

        # URL 设置
        tk.Label(container, text="请求 URL:").grid(row=0, column=0, sticky=tk.W, pady=(0, 5))
        url_entry = tk.Entry(container, textvariable=self.url_var, width=40)
        url_entry.grid(row=0, column=1, sticky=tk.EW, pady=(0, 5))

        # 产线编号
        tk.Label(container, text="产线编号:").grid(row=1, column=0, sticky=tk.W, pady=(0, 5))
        line_entry = tk.Entry(container, textvariable=self.line_code_var, width=40)
        line_entry.grid(row=1, column=1, sticky=tk.EW, pady=(0, 5))

        # 工位编号
        tk.Label(container, text="工位编号:").grid(row=2, column=0, sticky=tk.W, pady=(0, 5))
        station_entry = tk.Entry(container, textvariable=self.station_code_var, width=40)
        station_entry.grid(row=2, column=1, sticky=tk.EW, pady=(0, 5))

        # SN 数量
        tk.Label(container, text="SN 数量:").grid(row=3, column=0, sticky=tk.W, pady=(0, 5))
        count_entry = tk.Entry(container, textvariable=self.sn_count_var, width=40)
        count_entry.grid(row=3, column=1, sticky=tk.EW, pady=(0, 5))

        # 是否需要结果输入框
        result_check = tk.Checkbutton(
            container,
            text="需要结果输入框",
            variable=self.need_result_var,
            onvalue=True,
            offvalue=False
        )
        result_check.grid(row=4, column=0, columnspan=2, sticky=tk.W, pady=(0, 5))

        # 判断字符 1
        tk.Label(container, text="判断字符 1:").grid(row=5, column=0, sticky=tk.W, pady=(0, 5))
        judge_char_1_entry = tk.Entry(container, textvariable=self.judge_char_1_var, width=40)
        judge_char_1_entry.grid(row=5, column=1, sticky=tk.EW, pady=(0, 5))

        # 判断结果 1
        tk.Label(container, text="判断结果 1:").grid(row=6, column=0, sticky=tk.W, pady=(0, 5))
        judge_result_1_entry = tk.Entry(container, textvariable=self.judge_result_1_var, width=40)
        judge_result_1_entry.grid(row=6, column=1, sticky=tk.EW, pady=(0, 5))

        # 判断字符 2
        tk.Label(container, text="判断字符 2:").grid(row=7, column=0, sticky=tk.W, pady=(0, 5))
        judge_char_2_entry = tk.Entry(container, textvariable=self.judge_char_2_var, width=40)
        judge_char_2_entry.grid(row=7, column=1, sticky=tk.EW, pady=(0, 5))

        # 判断结果 2
        tk.Label(container, text="判断结果 2:").grid(row=8, column=0, sticky=tk.W, pady=(0, 5))
        judge_result_2_entry = tk.Entry(container, textvariable=self.judge_result_2_var, width=40)
        judge_result_2_entry.grid(row=8, column=1, sticky=tk.EW, pady=(0, 10))

        # 保存按钮
        button_frame = tk.Frame(container)
        button_frame.grid(row=9, column=0, columnspan=2, pady=(10, 0))

        tk.Button(
            button_frame,
            text="保存设置",
            command=lambda: [self.save_settings() and settings_window.destroy()],
            width=15
        ).pack()

        # 配置网格权重
        container.columnconfigure(1, weight=1)
        settings_window.columnconfigure(0, weight=1)
        settings_window.rowconfigure(0, weight=1)

    def update_sn_inputs(self):
        """更新 SN 输入框布局"""
        try:
            # 清除旧输入框
            for widget in self.sn_frame.winfo_children():
                widget.destroy()

            self.sn_entries = []
            self.result_entries = []

            count = int(self.sn_count_var.get())
            if count <= 0:
                raise ValueError("SN 数量必须大于 0")

            need_result = self.need_result_var.get()

            # 创建新输入框
            for i in range(count):
                # SN 输入框
                tk.Label(self.sn_frame, text=f"SN {i + 1}:").grid(row=i, column=0, padx=5, pady=2, sticky=tk.E)
                sn_entry = tk.Entry(self.sn_frame, width=20)
                sn_entry.grid(row=i, column=1, padx=5, pady=2)
                self.sn_entries.append(sn_entry)

                # 结果输入框（如果需要）
                if need_result:
                    tk.Label(self.sn_frame, text=f"结果 {i + 1}:").grid(row=i, column=2, padx=5, pady=2, sticky=tk.E)
                    result_entry = tk.Entry(self.sn_frame, width=20)
                    result_entry.grid(row=i, column=3, padx=5, pady=2)
                    self.result_entries.append(result_entry)

                # 绑定回车键事件
                if need_result:
                    sn_entry.bind("<Return>", lambda e, i=i: self.result_entries[i].focus_set())
                    if i < count - 1:
                        result_entry.bind("<Return>", lambda e, i=i: self.sn_entries[i + 1].focus_set())
                    else:
                        result_entry.bind("<Return>", lambda e: self.send_request())
                else:
                    if i < count - 1:
                        sn_entry.bind("<Return>", lambda e, i=i: self.sn_entries[i + 1].focus_set())
                    else:
                        sn_entry.bind("<Return>", lambda e: self.send_request())

            if self.sn_entries:
                self.sn_entries[0].focus_set()

        except ValueError as e:
            messagebox.showerror("错误", f"无效的 SN 数量: {str(e)}")
            self.sn_count_var.set("1")
            self.update_sn_inputs()


if __name__ == "__main__":
    root = tk.Tk()
    app = APIApp(root)
    root.mainloop()
    
